/*
 * @Author: ischen.x ischen.x@foxmail.com
 * @Date: 2025-01-03 14:51:24
 * @LastEditors: ischen.x ischen.x@foxmail.com
 * @LastEditTime: 2025-03-05 15:36:44
 * 
 * Copyright (c) 2025 by fhchengz, All Rights Reserved. 
 */
#include "tlv.h"
#include "ringbuff.h"
#include <string.h>
#include <stdio.h>

#define HEADER_1 0x55
#define HEADER_2 0xAA
#define MAX_BUF_LEN 255

typedef int (*tlv_crc_t)(uint8_t *data, uint8_t len);

static tlv_crc_t tlv_crc;

int tlv_set_crc_function(tlv_crc_t tlv_fun)
{
    int ret = 0;
    if (tlv_fun != NULL){
        tlv_crc = tlv_fun;
    } else {
        ret = -1;
    }
    return ret;
}

int tlv_pack(head_type head, tag_type tag, uint8_t *value, length_type value_len, uint8_t **output_buffer, uint8_t *out_len)
{
    if (value == NULL || output_buffer == NULL) {
        return TLV_PACK_ERR_NULL;  // 检查指针是否为空
    }

    // 计算总长度// head + tag + length + value + crc
    uint8_t total_len = sizeof(head_type) + sizeof(tag_type) + sizeof(length_type) + value_len +  + sizeof(crc_type);  

    // 动态分配内存
    *output_buffer = (uint8_t*)malloc(total_len);
    if (*output_buffer == NULL) {
        return TLV_PACK_ERR_MEMORY;  // 内存分配失败
    }

    uint8_t *ptr = *output_buffer;

    // 填充头部字段
    *(head_type*)ptr = head; ptr += sizeof(head_type);

    // 填充标签字段
    *(tag_type*)ptr = tag; ptr += sizeof(tag_type);

    // 填充长度字段
    *(value_type*)ptr = value_len; ptr += sizeof(value_type);

    // 复制值数据到 buffer
    memcpy(ptr, value, value_len); ptr += value_len;

    // 计算 CRC，如果有 CRC 函数
    if (tlv_crc != NULL) {
        *ptr = tlv_crc(*output_buffer, total_len - sizeof(crc_type));  //排除CRC 字段本身
    } else {
        *ptr = 0;  // 默认 CRC 为 0
    }

    // 设置输出数据长度
    if (out_len != NULL) {
        *out_len = total_len;
    }

    return TLV_PACK_SUCCESS;  // 成功
}

uint8_t crc8(const uint8_t *data, uint8_t len) {
    uint8_t crc = 0x00;
    for(uint8_t i=0; i<len; i++) {
        crc ^= data[i];
        for(uint8_t j=0; j<8; j++) {
            if(crc & 0x80) {
                crc = (crc << 1) ^ 0x07;
            } else {
                crc <<= 1;
            }
        }
    }
    return crc;
}

static void process_data(uint8_t *data, uint8_t len, tlv_frame_t **fream_out) {
    // printf("Valid Frame: ");
    // for(int i=0; i<len; i++) {
    //     printf("%02X ", data[i]);
    // }
    // printf("\n");
    tlv_frame_t *frame = (tlv_frame_t*)malloc(sizeof(tlv_frame_t));
    frame->head = *(head_type*)data;
    data += sizeof(head_type);
    frame->tag = *(tag_type*)data;
    data += sizeof(tag_type);
    frame->length = len - sizeof(head_type) - sizeof(tag_type) - sizeof(length_type);
    data += sizeof(length_type);
    frame->value = (uint8_t*)malloc(frame->length);
    frame->value = memcpy(frame->value, data, frame->length);
    data += frame->length;
    frame->crc = *(crc_type*)data;
    *fream_out = frame;
}

int tlv_free(tlv_frame_t *frame) 
{
    if (frame!= NULL) {
        if (frame->value!= NULL) {
            free(frame->value);
        }
        free(frame);
    }
    return 0;
}
/*s
 55 0 1 1 0 55 0 1 2 0 55 0 1 3 
0 55 0 1 4 0 55 0 1 5 0 55 0 1 
6 0 55 0 1 7 0 55 0 1 8 0 55 0 
1 9 0 55 0 1 a 0 55 0 1 b 0 55 
0 1 c 0 55 0 1 d 0 55 0 1 e 0 
 55 0 1 f 0 55 0 1 10 0 55 0 1 11 
 0 55 0 1 12 0 55 0 1 13 0 55 0 1 
 14 0 55 0 1 15 0 55 0 1 16 0 55 0 
 1 17 0 55 0 1 18 0 55 0 1 19 0 55 
 0 1 1a 0 55 0 1 1b 0 55 0 1 1c 0 
 55 0 1 1d 0 55 0 1 1e 0 55 0 1 1f 
 0 55 0 1 20 0 55 0 1 21 0 55 0 1 
 22 0 55 0 1 23 0 55 0 1 24 0 55 0 
 1 25 0 55 0 1 26 0 55 0 1 27 0 55 
 0 1 28 0 55 0 1 29 0 55 0 1 2a 0
 55 0 1 2b 0 55 0 1 2c 0 55 0 1 2d
 0 55 0 1 2e 0 55 0 1 2f 0 55 0 1
 30 0 55 0 1 31 0 55 0 1 32 0 55 0
 1 33 0 55 0 1 34 0 55 0 1 35 0 55
 0 1 36 0 55 0 1 37 0 55 0 1 38 0
 55 0 1 39 0 55 0 1 3a 0 55 0 1 3b
 0 55 0 1 3c 0 55 0 1 3d 0 55 0 1
 3e 0 55 0 1 3f 0 55 0 1 40 0 55 0
 1 41 0 55 0 1 42 0 55 0 1 43 0 55
 0 1 44 0 55 0 1 45 0 55 0 1 46 0
 55 0 1 47 0 55 0 1 48 0 55 0 1 49
 0 55 0 1 4a 0 55 0 1 4b 0 55 0 1
 4c 0 55 0
 */

int tlv_unpack(uint8_t data_in, tlv_frame_t **fream_out)
{
    int ret = 0;
    static uint8_t recv_buf[MAX_BUF_LEN];
    static uint8_t buf_index = 0;
    static uint8_t expected_length = 0;
    static ParserState state = STATE_SEARCH_HEADER;
    uint8_t byte = data_in;
    switch(state) {
    case STATE_SEARCH_HEADER:
        if(buf_index == 0 && byte == HEADER_1) {
            recv_buf[buf_index++] = byte;
        } 
        else if(buf_index == 1 && byte == HEADER_2) {
            recv_buf[buf_index++] = byte;
            state = STATE_READ_TAG;
        } 
        else {
            buf_index = 0; 
        }
        break;

    case STATE_READ_TAG:
        recv_buf[buf_index++] = byte;
        state = STATE_READ_LENGTH;
        break;

    case STATE_READ_LENGTH: {
        recv_buf[buf_index++] = byte;
        uint8_t value_length = byte;
        expected_length = 5 + value_length;
        state = STATE_READ_DATA;
        break;
    }

    case STATE_READ_DATA:
        recv_buf[buf_index++] = byte;
        // ����Ƿ�ﵽԤ�ڳ���
        if(buf_index >= expected_length - 1) { // -1��Ϊ����CRC
            state = STATE_READ_CRC;
        }
        break;

    case STATE_READ_CRC:
        recv_buf[buf_index++] = byte;
        // ----------- ���ݴ����� -----------
        // 1. ��֤CRC
        uint8_t received_crc = byte;
        uint8_t calc_crc = crc8(recv_buf, buf_index-1); // ����ǰn-1�ֽ�
        
        //if(calc_crc == received_crc) {
            // 2. ��ȡ��Ч���ݣ�Header+Tag+Length+Value��
            process_data(recv_buf, buf_index-1, fream_out);
        //}
        
        //printf("%#x,%#x,%#x,%#x,%#x,%#x,%#x,%#x,%#x\r\n",recv_buf[0],recv_buf[1],recv_buf[2],recv_buf[3],recv_buf[4],recv_buf[5],recv_buf[6],recv_buf[7],recv_buf[8]);
        // 3. ����״̬��
        memset(recv_buf, 0, MAX_BUF_LEN);
        buf_index = 0;
        state = STATE_SEARCH_HEADER;
        ret = 1;
        break;
    }
    if(buf_index >= MAX_BUF_LEN) {
        memset(recv_buf, 0, MAX_BUF_LEN);
        buf_index = 0;
        state = STATE_SEARCH_HEADER;
    }
    return ret;
}


